package com.stottlerhenke.simbionic.editor;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

import javax.swing.Icon;
import javax.swing.ImageIcon;

import com.stottlerhenke.simbionic.api.SB_ParamType;
import com.stottlerhenke.simbionic.api.SB_VarType;
import com.stottlerhenke.simbionic.common.parser.EParseFlags;
import com.stottlerhenke.simbionic.common.parser.SB_ExpressionNode;
import com.stottlerhenke.simbionic.editor.gui.ComponentRegistry;
import com.stottlerhenke.simbionic.editor.gui.SB_ProjectBar;
import com.stottlerhenke.simbionic.editor.parser.SB_ParseNode;
import com.stottlerhenke.simbionic.editor.parser.SB_ParserEditorInterface;


public class SB_Variable extends UserObject {

    private static final long serialVersionUID = 2302585093L + 5;

    public final static int kFloat = 0;
    public final static int kString = 1;
    public final static int kEntity = 2;
    public final static int kVector = 3;
    public final static int kData = 4;
    public final static int kInteger = 5;
    public final static int kBoolean = 6;
    public final static int kAny = 7;
    public final static int kArray = 8;
    public final static int kTable = 9;
    public final static int kUser = 0xA;
    
    /**
     * @deprecated
     */
    public final static String[] kTypeNames = 
    { "float", "string", "entity", "vector", "data", "integer", 
      "boolean", "any", "array", "table", "user" };

    protected int _type; // variable type
    protected boolean _editable = true;
    protected Object _userData = null;
    protected ImageIcon _icon = null;

    transient protected String _fullName = null;

    public SB_Variable() // constructor for Externalizable object
    {
    }

    public SB_Variable(String name) {
        super(name);
        _type = kInteger;
    }

    public SB_Variable(String name, int type) {
        super(name);
        _type = type;
    }

    public String toString() {
        if (_editing)
            return _name;
        else {
            if (_fullName == null)
            	_fullName = _name + " : " + getTypeName();
            return _fullName;
        }
    }

    public void setName(String name) {
        super.setName(name);
        _fullName = null;
    }

    public int getType() {
        return _type;
    }

    public void setType(int type) {
        _type = type;
        _fullName = null;
    }
    
    public String getTypeName(){
    	SB_TypeManager typeManager = ComponentRegistry.getProjectBar().getTypeManager();
    	SB_VarType newType = SB_TypeManager.convertOldTypeId(_type);
    	return typeManager.getTypeName(newType);
    }
    
    
    /**
     * @deprecated
     */
    public static int typeToInt(String type){
    	for (int i=0;i<kTypeNames.length;i++){
    		if (kTypeNames[i].equals(type))
    			return i;
    	}
    	return -1;
    }

    public boolean isCellEditable() {
        return _editable || SimBionicEditor.DEV;
    }

    public Icon getIcon() {
        if (_icon == null) _icon = Util.getImageIcon("Local.gif");
        return _icon;
    }

    public void compileSIM(BufferedWriter out, SB_TypeManager typeManager) {
        try {
        	SB_VarType id = SB_TypeManager.convertOldTypeId(_type);
            out.write(SB_ProjectBar.getPString(_name) + " " + typeManager.idToSimType(id));

            // if the type is a class, mark the class is in use
            if (id.getState() >= SB_VarType.kCLASS_START.getState())
            {
                String fullQualifiedName = typeManager.getTypePackage(id);
            	ComponentRegistry.getProjectBar().getCatalog().lookupClass(fullQualifiedName).setInUse(true);
            }

        } catch (IOException exception) {
            System.err.println("i/o exception");
        }
    }

    /**
     * convert from combo box position to SIM variable type index
     * @deprecated
     */
    protected SB_ParamType posToIndex(int pos) {
        switch (pos) {
        case kFloat:
            return SB_ParamType.kSB_Float;
        case kString:
            return SB_ParamType.kSB_String;
        case kEntity:
            return SB_ParamType.kSB_Entity;
        case kVector:
            return SB_ParamType.kSB_Vector;
        case kData:
            return SB_ParamType.kSB_Data;
        case kInteger:
            return SB_ParamType.kSB_Integer;
        case kBoolean:
            return SB_ParamType.kSB_Boolean;
        case kAny:
            return SB_ParamType.kSB_StrConst;
        case kArray:
            return SB_ParamType.kSB_Array;
        case kTable:
            return SB_ParamType.kSB_Array;
        default:
            return SB_ParamType.kSB_Invalid;
        }
    }

    protected SB_ParseNode parseValue(String value) {
        SB_ExpressionNode tree = null;
        SB_ParseNode ptree = null;

        switch (_type) {
        case kFloat:
        case kInteger:
        case kBoolean:
        case kVector:
        case kArray:
        case kTable:
            tree = SB_ParserEditorInterface.getParser().Parse(value, EParseFlags.kNoVarsNoFuncs);
            ptree = (SB_ParseNode) (tree);
            break;

        case kString:
            tree = SB_ParserEditorInterface.getParser().Parse(value, EParseFlags.kString);
            ptree = (SB_ParseNode) (tree);
            break;

        case kEntity:
            // user does not specify value for entity
            break;

        case kData:
            // user does not specify value for data
            break;
        }

        return ptree;
    }

    public void writeExternal(ObjectOutput out) throws IOException {
    	super.writeExternal(out);

    	out.writeInt(_type);

    	out.writeBoolean(_editable);
    	out.writeObject(_userData);
    }

    public void readExternal(ObjectInput in) throws ClassNotFoundException,
            IOException {
        super.readExternal(in);

        int loading = SB_ProjectBar.getLoading();
        
        _type = in.readInt();
        
        if ((loading == SB_ProjectBar.LOADING_SBP && (SB_ProjectBar.getSBPVersion() == 5 || SB_ProjectBar.getSBPVersion() == 6))
                || (loading == SB_ProjectBar.LOADING_APD && SB_ProjectBar.getAPDVersion() == 3)
                || (loading == SB_ProjectBar.LOADING_BTN && SB_ProjectBar.getBTNVersion() == 5))
        {
        	String typeName = (String) in.readObject();
        }
        
        _editable = in.readBoolean();
        
        if ((loading == SB_ProjectBar.LOADING_SBP && SB_ProjectBar.getSBPVersion() >= 3)
                || (loading == SB_ProjectBar.LOADING_APD && SB_ProjectBar.getAPDVersion() >= 2)
                || (loading == SB_ProjectBar.LOADING_BTN && SB_ProjectBar.getBTNVersion() >= 2)) 
        	_userData = in.readObject();
    }

    /**
     * @return Returns the editable.
     */
    public boolean isEditable() {
        return _editable;
    }

    /**
     * @param editable
     *            The editable to set.
     */
    public void setEditable(boolean editable) {
        _editable = editable;
    }

    /**
     * @return Returns the userData.
     */
    public Object getUserData() {
        return _userData;
    }

    /**
     * @param userData
     *            The userData to set.
     */
    public void setUserData(Object userData) {
        _userData = userData;
    }
}